import select
import socket
import sys
import queue
from queue import Queue

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setblocking(False)

server_address = ('localhost', 6868)
server.bind(server_address)
print("http://localhost:6868/")

server.listen(5)

message_queues = {}

READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
READ_WRITE = READ_ONLY | select.POLLOUT

TIMEOUT = 1000
poller = select.poll() 

poller.register(server, READ_ONLY)
fd_to_socket = {server.fileno(): server,}
while True:
    events = poller.poll(TIMEOUT) 
    for fd, flag in events:
        s = fd_to_socket[fd]
        if flag & (select.POLLIN | select.POLLPRI):
            if s is server: 
                connection, client_address = s.accept()
                print('new conn:', client_address)
                connection.setblocking(0)
                fd_to_socket[connection.fileno()] = connection
                poller.register(connection, READ_ONLY)
                message_queues[connection] = Queue() 
            else:
                data = s.recv(1024)
                if data: 
                    print('new data "%s" from %s' % (data, s.getpeername()))
                    message_queues[s].put(data)
                    poller.modify(s, READ_WRITE)
                else:
                    print('read none close', client_address)
                    poller.unregister(s)
                    s.close()
                    del message_queues[s]

        elif flag & select.POLLHUP:
            print('close hup', client_address)
            poller.unregister(s)
            s.close()

        elif flag & select.POLLOUT:
            try:
                next_msg = message_queues[s].get_nowait()
            except queue.Empty:
                print('Queue Empty', s.getpeername())
                poller.modify(s, READ_ONLY)
            else:
                print('send "%s" to  %s' % (next_msg, s.getpeername()))
                s.send(next_msg)

        elif flag & select.POLLERR:
            print('exception:', s.getpeername())
            poller.unregister(s)
            s.close()
            del message_queues[s]

